package jEDF.Hypnogram;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.*;

import jEDF.EDF.*;
import jEDF.Exceptions.*;
import jEDF.JEDF.*;
import jEDF.PreciseScoring.*;

/**
 *
 * <p>Titre : jEDF</p>
 * <p>Description : Java European Data Format Viewer and Analyser</p>
 * <p>Author : Nizar Kerkeni</p>
 * <p>Copyright : Copyright (c) 2003-2006</p>
 * <p>Version 2.0</p>
 */
public class JEDFHypnogram extends JPanel {

    private float dashLength = 5f;
    private Color xAxisColor = Color.LIGHT_GRAY;
    //private int totDurationInSeconds = 0;
    private int epochDuration = 0;
    private int labelsWidth = 0;
    private short[] data = null;
    private short[] data_gabarito = null;
    private RandomAccessFile rafHypno = null;
    private RandomAccessFile rafGabarito = null;
    private Color captionColor = Color.RED;
    private Color yAxisColorEditable = Color.blue;
    private Color yAxisColorNotEditable = Color.red;
    private Color hypnogramColor = Color.BLACK;
    private Color REMColor = Color.RED;
    private boolean modified = false;
    private boolean readOnly = false;
    private final int UNESCORED = 0;
    private final int AWAKE = 1;
    private final int REM = 2;
    private final int N1 = 3;
    private final int N2 = 4;
    private final int N3 = 5;
    private String[] labels = {"Un", "Wa", "Rem", "1", "2", "3"};
    private Color[] stageColors = {Color.BLACK, Color.MAGENTA, Color.RED, new Color(0x8b4513), Color.GREEN, Color.BLUE};
    private String[] midLabels = {"Uns", "Awa", "Rem", "St1", "St2", "St4"};
    private String[] longLabels = {
        JEDFMainWindow.getLocalizedString("Unscored"),
        JEDFMainWindow.getLocalizedString("Awake"),
        JEDFMainWindow.getLocalizedString("Rem"),
        JEDFMainWindow.getLocalizedString("Stage 1"),
        JEDFMainWindow.getLocalizedString("Stage 2"),
        JEDFMainWindow.getLocalizedString("Stage 3"),
        JEDFMainWindow.getLocalizedString("Stage 4"),
        JEDFMainWindow.getLocalizedString("Movement")};
    //private EDFFile edfFile = null;
    private JEDFMainWindow mainWindow = null;
    private Polysomnograph polysomnograph = null;
    private JEDFStagesPanel stagesPanel = null;
    private PreciseScoring preciseScoring = null;
    private boolean areDataProcessed = false;
    private String m_srtFilenameGabarito = "";
    private boolean m_bCompareScoring = false;

    public boolean getCompareScoring() {
        return m_bCompareScoring;
    }

    public void setCompareScoring(boolean m_bCompareScoring) {
        this.m_bCompareScoring = m_bCompareScoring;
    }

    /**
     * @param mainWindow the window containing this hypnogram
     * @param stagesPanel the panel displaying this hypnogram stages
     */
    public JEDFHypnogram(JEDFMainWindow mainWindow, JEDFStagesPanel stagesPanel) {
        this.mainWindow = mainWindow;
        this.stagesPanel = stagesPanel;

        setBackground(Color.white);
        addMouseListener(new MouseAdapter() {

            public void mouseClicked(MouseEvent arg0) {
                onMouseClick(arg0);
            }
        });
    }

    private void onMouseClick(MouseEvent arg0) {
        if (isCleared()) {
            return;
        }
        if (polysomnograph == null) {
            return;
        }
        //if(edfFile==null)
        //  return;

        double x = arg0.getX();
        double width = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getWidth();
        width -= labelsWidth;
        x -= labelsWidth;

        if (mainWindow.getEDFFile() == null) {
            return;
        }

        int totDurationInSeconds = mainWindow.getEDFFile().getNbRecords()
                * mainWindow.getEDFFile().getRecordDuration();

        x /= width;
        x *= totDurationInSeconds;

        polysomnograph.setStartSecond((int) Math.round(x));
    }

    /* (non-Javadoc)
     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
     */
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2D = (Graphics2D) g;
        if (data != null) {
            draw(g2D);
        }
    }

    /**
     * @param edfFile the file to load the hypnogram from
     * @throws UserCancelException if the user cancelled his action
     * @throws FileNotFoundException if the file couldn't be opened
     */
    public void loadEDFFile(EDFFile edfFile)
            throws UserCancelException,
            FileNotFoundException,
            IOException {



        if (edfFile == null) {
            return;
        }

        clear();

        loadHypnogramGabarito();

        if (edfFile.isItAHypnogramRecord()) {
            loadHypnogramOnlyEDFFile(edfFile);
        } else {
            loadClassicEDFFile(edfFile);
        }
    }

    private void loadClassicEDFFile(EDFFile edfFile) {
        areDataProcessed = false;

        //this.edfFile = edfFile;

        int totDurationInRecords = edfFile.getNbRecords();
        epochDuration = edfFile.getRecordDuration();
        int totDurationInSeconds = totDurationInRecords * epochDuration;

        data = null;

        for (int i = 0; i < edfFile.getNbSignals(); i++) {
            if (edfFile.getSignal(i).isEmbeddedHypnogram()) {
                EDFSignal signal = edfFile.getSignal(i);
                data = signal.readSeconds(0, (int) totDurationInSeconds);
                break;
            }
        }

        if (data != null) {
            processData();
        }
    }

    private void loadHypnogramOnlyEDFFile(EDFFile edfFile)
            throws
            FileNotFoundException {
        if (edfFile == null) {
            return;
        }

        EDFFile mainEDF = mainWindow.getEDFFile();

        if (mainEDF != null) {
            if (mainEDF.getNbRecords() != edfFile.getNbRecords()
                    && !mainEDF.isItAHypnogramRecord()) {
                JOptionPane.showMessageDialog(this,
                        JEDFMainWindow.getLocalizedString(
                        "The specified hypnogram does not have the same number")
                        + JEDFMainWindow.getLocalizedString(
                        "\nof epochs as the loaded EDF file."),
                        JEDFMainWindow.getLocalizedString(
                        "Warning"), JOptionPane.WARNING_MESSAGE);
            }
        }

        areDataProcessed = false;

        int totDurationInRecords = edfFile.getNbRecords();
        epochDuration = edfFile.getRecordDuration();
        int totDurationInSeconds = totDurationInRecords * epochDuration;

        data = null;

        EDFSignal signal = edfFile.getSignal(0);

        data = signal.readSeconds(0, (int) totDurationInSeconds);
        //data_gabarito = signal.readSeconds(0, (int) totDurationInSeconds);
        try {
            rafHypno = new RandomAccessFile(edfFile.getFile(), "rwd");
        } catch (FileNotFoundException fnfe) {
            rafHypno = new RandomAccessFile(edfFile.getFile(), "r");
            JOptionPane.showMessageDialog(this,
                    JEDFMainWindow.getLocalizedString(
                    "The specified file can only be opened in read-only mode."),
                    JEDFMainWindow.getLocalizedString(
                    "Warning"),
                    JOptionPane.WARNING_MESSAGE);
        }

        if (data != null) {
            processData();
        }
    }

    private void loadHypnogramGabarito()
            throws FileNotFoundException {

        EDFFile edfFile = null;
        data_gabarito = null;
        if (m_srtFilenameGabarito != "") {
            try {
                edfFile = new EDFFile(new File(m_srtFilenameGabarito));
            } catch (IOException ex) {
                //Logger.getLogger(JEDFHypnogram.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (edfFile == null) {
            return;
        }



        EDFFile mainEDF = mainWindow.getEDFFile();




        int totDurationInRecords = edfFile.getNbRecords();
        epochDuration = edfFile.getRecordDuration();
        int totDurationInSeconds = totDurationInRecords * epochDuration;

        EDFSignal signal = edfFile.getSignal(0);

        data_gabarito = signal.readSeconds(0, (int) totDurationInSeconds);
        try {
            rafGabarito = new RandomAccessFile(edfFile.getFile(), "rwd");
        } catch (FileNotFoundException fnfe) {
            rafGabarito = new RandomAccessFile(edfFile.getFile(), "r");
            JOptionPane.showMessageDialog(this,
                    JEDFMainWindow.getLocalizedString(
                    "The specified file can only be opened in read-only mode."),
                    JEDFMainWindow.getLocalizedString(
                    "Warning"),
                    JOptionPane.WARNING_MESSAGE);
        }

        if (data_gabarito != null) {
            processDataGabarito();
        }
        try {
            rafGabarito.close();
        } catch (IOException ex) {
            Logger.getLogger(JEDFHypnogram.class.getName()).log(Level.SEVERE, null, ex);
        }
        edfFile.close();
    }

    /**
     * @param signal the signal to load the hypnogram from
     * @throws NotAHypnogramException if the signal does not contain hypnogram data
     * @throws UserCancelException if the user cancelled his action
     */
    public void loadSignalData(EDFSignal signal)
            throws NotAHypnogramException,
            UserCancelException {
        clear();

        epochDuration = mainWindow.getEDFFile().getRecordDuration();
        int totDurationInSeconds = mainWindow.getEDFFile().getRecordDuration()
                * mainWindow.getEDFFile().getNbRecords();

        if (!signal.isEmbeddedHypnogram()) {
            throw new NotAHypnogramException();
        }

        data = signal.readSeconds(0, (int) totDurationInSeconds);
        if (data != null) {
            processData();
        }
    }

    private int toStage(int value) {
        switch (value) {
            //Unscored
            case 0:
                return -1;

            //Awake
            case 1:
                return 0;

            //REM
            case 2:
                return 4;

            //N1
            case 3:
                return 1;

            //N2
            case 4:
                return 2;

            //N3
            case 5:
                return 3;

        }
        return -1;

    }

    private void draw(Graphics2D g) {
        /** Lissage du texte et des dessins */
        //((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        int startOrdinate = drawLabels(g);
        drawXAxis(g, startOrdinate);

        double width = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getWidth();
        double height = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getHeight();

        int coefHeight = (int) (height / labels.length);

        float coefWidth = (float) ((width - (double) startOrdinate)
                / (double) data.length);

        int previousPoint = data[0] * coefHeight + Math.round(coefHeight / 2);
        int currentPoint = 0;

        Color originalColor = g.getColor();
        g.setColor(hypnogramColor);

        float abscissa = startOrdinate;

        int total = 0;
        int acertos = 0;
        int eficiencia = 0;

        for (int i = 0; i < data.length; i++) {
            currentPoint = coefHeight * data[i] + Math.round(coefHeight / 2);

            if (m_bCompareScoring) {
                g.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT,
                        BasicStroke.JOIN_MITER));
                g.setColor(stageColors[data[i]]);
            } else {
                g.setStroke(new BasicStroke(1));
                g.setColor(hypnogramColor);
            }



            if (data[i] == REM) {
                //    g.setColor(REMColor);
                g.setStroke(new BasicStroke(4, BasicStroke.CAP_BUTT,
                        BasicStroke.JOIN_MITER));
            }

            //Efetua a comparação entre o auto-scoring e o hipnograma manual
            if (data_gabarito != null && m_bCompareScoring) {
                g.setColor(stageColors[data_gabarito[i]]);

                //confere N3
                if (data[i] == AWAKE || data_gabarito[i] == AWAKE
                        || data[i] == N3 || data_gabarito[i] == N3) {
                    total++;
                    if (data[i] == data_gabarito[i]) {
                        acertos++;
                    }
                }
            }
            g.drawLine((int) abscissa, currentPoint,
                    (int) (abscissa + coefWidth), currentPoint);
            g.setStroke(new BasicStroke(1));

            g.setColor(hypnogramColor);
            if (currentPoint != previousPoint) {
                g.drawLine((int) abscissa - 1,
                        Math.min(currentPoint, previousPoint),
                        (int) (abscissa - 1),
                        Math.max(currentPoint, previousPoint));
            }
            abscissa += coefWidth;
            previousPoint = currentPoint;
        }


        g.setColor(originalColor);

        drawYAxis(g, startOrdinate);


        if (m_bCompareScoring) {
            String result = "";
            if (data_gabarito != null) {

                eficiencia = acertos * 100 / total;
                result = result + "                  Scoring Accuracy: " + eficiencia + "%";


            } else {
                result = result + "                  Scoring Accuracy: N/A - '" + m_srtFilenameGabarito + "' not found";
            }


            if (mainWindow.getStatusBar().getText().indexOf(result) == -1) {
                mainWindow.getStatusBar().setText(mainWindow.getStatusBar().getText() + result);
            }
        }

    }

    private int drawLabels(Graphics2D g) {
        double height = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getHeight();

        int coefHeight = (int) height / labels.length;
        FontMetrics fontMetrics = g.getFontMetrics();

        Color cTemp = g.getColor();
        g.setColor(captionColor);

        int maxWidth = Integer.MIN_VALUE;

        for (int i = 1; i <= labels.length; i++) {
            if (m_bCompareScoring)
            {
                g.setColor(stageColors[i - 1]);
            }
            g.drawString(labels[i - 1], 0, coefHeight * i);
            int strWidth = (int) fontMetrics.getStringBounds(labels[i - 1], g).
                    getWidth();
            if (strWidth > maxWidth) {
                maxWidth = strWidth;
            }
        }

        g.setColor(cTemp);

        labelsWidth = maxWidth;

        return maxWidth;
    }

    private void drawXAxis(Graphics2D g, int xOffset) {
        int coefHeight = (int) SwingUtilities.calculateInnerArea(this,
                new Rectangle()).getHeight() / labels.length;

        Stroke tempStroke = g.getStroke();

        float[] dash = {dashLength, dashLength};
        g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_SQUARE,
                BasicStroke.JOIN_BEVEL, 1f, dash, 0f));

        Color currentColor = g.getColor();
        g.setColor(xAxisColor);

        int height = Math.round(coefHeight / 2);
        int width = (int) SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getWidth();

        for (int i = 0; i < labels.length; i++) {
            g.drawLine(xOffset, height, width, height);
            height += coefHeight;
        }

        g.setStroke(tempStroke);
        g.setColor(currentColor);

    }

    /**
     * @param file the file where this hypnogram will be recorded
     * @param recordDuration the desired hypnogram record duration
     * @throws FileNotFoundException if the file cannot be accessed
     */
    public void createHypnogram(File file, int recordDuration)
            throws
            FileNotFoundException, IOException {
        EDFFile edfFile = mainWindow.getEDFFile();

        loadHypnogramGabarito();

        if (edfFile == null) {
            return;
        }

        areDataProcessed = false;

        int totDurationInRecords = edfFile.getNbRecords();
        epochDuration = edfFile.getRecordDuration();
        int totDurationInSeconds = totDurationInRecords * epochDuration;

        rafHypno = new RandomAccessFile(file, "rwd");

        epochDuration = recordDuration;

        data = new short[(int) Math.ceil((double) totDurationInSeconds
                / (double) recordDuration)];

        //numRecord = 0;

        for (int i = 0; i < data.length; i++) {
            data[i] = 9;
        }

        processData();

        saveToEDFFile(file);
    }

    /**
     * clear this panel, effectively emptying it
     * @throws UserCancelException if the user changed his mind
     */
    public void clear()
            throws UserCancelException {
        if (hasLinkedFile()) {
            try {
                rafHypno.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            if (!isCleared() && modified) {
                if (JOptionPane.showConfirmDialog(this.getParent(),
                        JEDFMainWindow.getLocalizedString("You are attempting to close a modified hypnogram without it being saved first.\nAre you sure you want to continue ?"),
                        JEDFMainWindow.getLocalizedString("Warning"),
                        JOptionPane.YES_NO_OPTION)
                        == JOptionPane.NO_OPTION) {
                    throw new UserCancelException();
                }
            }
        }

        if (preciseScoring != null) {
            preciseScoring.clear();
        }

        modified = false;
        readOnly = false;
        data = null;
        rafHypno = null;
        //edfFile=null;
        //numRecord = 0;
        //totDurationInSeconds = 0;
        epochDuration = 0;
        stagesPanel.clear();
        areDataProcessed = false;

    }

    /**
     * @return whether this panel is cleared or not
     */
    public boolean isCleared() {
        return data == null;
    }

    private void drawYAxis(Graphics2D g, int xOffset) {
        double width = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getWidth() - xOffset;
        double height = SwingUtilities.calculateInnerArea(this, new Rectangle()).
                getHeight();

        float coefWidth = (float) width / (float) data.length;

        coefWidth *=
                ((double) polysomnograph.getEpochDuration()
                / (double) epochDuration);

        float xCoordinate = (float) xOffset
                + (coefWidth * (float) polysomnograph.getStartSecond()
                / (float) polysomnograph.getEpochDuration());

        Color cTemp = g.getColor();
        if (isWritable()) {
            g.setColor(yAxisColorEditable);
        } else {
            g.setColor(yAxisColorNotEditable);
        }

        g.drawRect((int) xCoordinate, 0, (int) coefWidth, (int) height - 1);

        g.setColor(cTemp);
    }

    /*public void moveToRecord(int numRecord){
    if(data==null)
    return;

    float j = (float)polysomnograph.getNbSecondsToDisplay() / (float)recordDurationInSeconds;

    if(numRecord>=0&&numRecord*j<data.length){
    this.numRecord=(int)(numRecord*j);
    }
    stagesPanel.updateLabels(getLabels());
    }*/
    public void repaint() {
        super.repaint();
        updateStagesPanel();
    }

    private void updateStagesPanel() {
        if (stagesPanel == null) {
            return;
        }

        String[] result = new String[8];

        for (int i = 0; i < result.length; i++) {
            result[i] = "---";
        }

        if (data == null || !areDataProcessed) {
            stagesPanel.updateLabels(result);
            return;
        }

        int numRecord = getCurrentRecord();

        for (int i = numRecord - 6; i < numRecord + 2; i++) {
            if (i >= 0 && i < data.length) {
                result[i - numRecord + 6] = longLabels[data[i]];
            }
        }

        stagesPanel.updateLabels(result);
    }

    /**
     * @param preciseScoring set a precise scoring panel to this hypnogram
     */
    public void setPreciseScoring(PreciseScoring preciseScoring) {
        this.preciseScoring = preciseScoring;
    }

    /**
     * @return the record duration of this hypnogram
     */
    public int getEpochDuration() {
        return epochDuration;
    }

    private void writeStage(int state) {

        if (preciseScoring.hasFocus()) {
            preciseScoring.setHypnogramState(state);
            return;
        }

        if (!isWritable()) {
            return;
        }

        data[getCurrentRecord()] = (short) state;
        updateFile();
        modified = true;

        if (preciseScoring.canBeDisplayed()) {
            preciseScoring.setFocus(true);
            preciseScoring.setAll(state);
        } else {
            polysomnograph.incrementStartRecord();
        }

        updateStagesPanel();
        //mainWindow.updateStatusBar();
    }

    /**
     * set the current stage to 1
     */
    public void setStage1() {
        writeStage(3);
    }

    /**
     * set the current stage to 2
     */
    public void setStage2() {
        writeStage(4);
    }

    /**
     * set the current stage to 3
     */
    public void setStage3() {
        writeStage(5);
    }

    /**
     * set the current stage to 4
     */
    public void setStage4() {
        writeStage(6);
    }

    /**
     * set the current stage to REM
     */
    public void setStageREM() {
        writeStage(2);
    }

    /**
     * set the current stage to MVT
     */
    public void setStageMVT() {
        writeStage(7);
    }

    /**
     * set the current stage to WAKE
     */
    public void setStageWAKE() {
        writeStage(1);
    }

    /**
     * set the current stage to UNSCORED
     */
    public void setStageUnscored() {
        writeStage(0);
    }

    /**
     * Transform hypnogram data so that they can be displayed easily.
     *
     */
    private void processData() {
        if (data == null) {
            return;
        }

        if (polysomnograph != null) {
            polysomnograph.setEpochDuration(epochDuration);
            polysomnograph.setStartSecond(0);
        }

        //mainWindow.setDisplayedEpochDuration(epochDuration);

        //numRecord=0;

        int point = 0;

        for (int i = 0; i < data.length; i++) {
            switch (data[i]) {
                case 0:
                    point = 1;
                    break;
                case 5:
                    point = 2;
                    break;
                case 6:
                    point = 7;
                    break;
                case 9:
                    point = 0;
                    break;
                default:
                    point = data[i] + 2;
            }
            data[i] = (short) point;
        }
        areDataProcessed = true;
        //stagesPanel.updateLabels(getLabels());
        updateStagesPanel();
    }

    /**
     * Transform hypnogram data so that they can be displayed easily.
     *
     */
    private void processDataGabarito() {
        if (data_gabarito == null) {
            return;
        }

        if (polysomnograph != null) {
            polysomnograph.setEpochDuration(epochDuration);
            polysomnograph.setStartSecond(0);
        }

        //mainWindow.setDisplayedEpochDuration(epochDuration);

        //numRecord=0;

        int point = 0;

        for (int i = 0; i < data_gabarito.length; i++) {
            switch (data_gabarito[i]) {
                case 0:
                    point = 1;
                    break;
                case 5:
                    point = 2;
                    break;
                case 6:
                    point = 7;
                    break;
                case 9:
                    point = 0;
                    break;
                default:
                    point = data_gabarito[i] + 2;
            }
            data_gabarito[i] = (short) point;
        }

        //stagesPanel.updateLabels(getLabels());
        updateStagesPanel();
    }

    /**
     * Transform back displayable values to standard hypnogram data.
     * @return a transformed copy of the displayable values
     */
    private short[] unprocessData() {
        if (data == null) {
            return null;
        }

        short[] result = (short[]) data.clone();

        int point = 0;

        for (int i = 0; i < result.length; i++) {
            switch (result[i]) {
                case 1:
                    point = 0;
                    break;
                case 2:
                    point = 5;
                    break;
                case 7:
                    point = 6;
                    break;
                case 0:
                    point = 9;
                    break;
                default:
                    point = result[i] - 2;
            }
            result[i] = (short) point;
        }

        return result;
    }

    /**
     * save the content of this hypnogram to an EDF file
     * and link it with the above mentionned EDF file so that every change can be recorded
     * @param file File
     */
    public void saveToEDFFile(File file) {
        try {
            FileOutputStream fos = new FileOutputStream(file);
            DataOutputStream dos = new DataOutputStream(fos);
            StringBuffer stringBuffer = null;

            rafHypno = new RandomAccessFile(file, "rwd");
            EDFFile edfFile = mainWindow.getEDFFile();

            // Global header

            byte[] globalHeader = edfFile.getUnprocessedHeader();

            fos.write(globalHeader, 0, 236);

            // we set the number of signals to 1
            /*
            8 ascii : number of data records (-1 if unknown)
            8 ascii : duration of a data record, in seconds
            4 ascii : number of signals (ns) in data record
             */

            stringBuffer = new StringBuffer("" + data.length);
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("" + epochDuration);
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("   1");
            stringBuffer.setLength(4);
            dos.writeBytes(stringBuffer.toString());

            /* EDFSignal Header
            ns * 16 ascii : ns * label (e.g. EEG FpzCz or Body temp)
            ns * 80 ascii : ns * transducer type (e.g. AgAgCl electrode)
            ns * 8 ascii : ns * physical dimension (e.g. uV or degreeC)
            ns * 8 ascii : ns * physical minimum (e.g. -500 or 34)
            ns * 8 ascii : ns * physical maximum (e.g. 500 or 40)
            ns * 8 ascii : ns * digital minimum (e.g. -2048)
            ns * 8 ascii : ns * digital maximum (e.g. 2047)
            ns * 80 ascii : ns * prefiltering (e.g. HP:0.1Hz LP:75Hz)
            ns * 8 ascii : ns * nr of samples in each data record
            ns * 32 ascii : ns * reserved
             */


            stringBuffer = new StringBuffer(JEDFMainWindow.getLocalizedString(
                    "Hypnogram"));
            stringBuffer.setLength(16);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer(JEDFMainWindow.getLocalizedString(
                    "0,1,2,3,4,5,6 and 9 are Wake,1,2,3,4,REM,MT and unscored, respectively"));
            stringBuffer.setLength(80);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer();
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("0.0");
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("9.0");
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("0");
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("9");
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer(edfFile.getFileName());
            stringBuffer.setLength(80);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer("1");
            stringBuffer.setLength(8);
            dos.writeBytes(stringBuffer.toString());

            stringBuffer = new StringBuffer();
            stringBuffer.setLength(32);
            dos.writeBytes(stringBuffer.toString());

            //data

            short[] rawData = unprocessData();

            ByteBuffer byteBuffer = ByteBuffer.allocate(rawData.length * 2);
            byteBuffer.order(ByteOrder.LITTLE_ENDIAN);

            for (int i = 0; i < rawData.length; i++) {
                byteBuffer.putShort(rawData[i]);
            }

            fos.write(byteBuffer.array());

            dos.flush();
            fos.flush();

            dos.close();
            fos.close();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

    }

    /**
     * Save the hypnogram as a text File.
     * @param file File the file to save in
     * @param dialog HypnogramToTextDialog
     */
    public void saveToTextFile(File file, HypnogramToTextDialog dialog) {
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "rw");
            raf.writeBytes("File : " + mainWindow.getEDFFile().getFileName() + "\n");
            for (int i = 0; i < data.length; i++) {
                raf.writeBytes(midLabels[data[i]] + "\n");
            }
            raf.close();
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(null, ex.getLocalizedMessage(),
                    JEDFMainWindow.getLocalizedString("Error"),
                    JOptionPane.ERROR_MESSAGE);
        }
        dialog.dispose();
    }

    /**
     * @param polysomnograph the polysomnograph corresponding to this hypnogram
     */
    public void setPolysomnograph(Polysomnograph polysomnograph) {
        this.polysomnograph = polysomnograph;
    }

    private void updateFile() {
        if (rafHypno == null || data == null) {
            return;
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(2);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);

        short point = 0;
        int numRecord = getCurrentRecord();

        switch (data[numRecord]) {
            case 1:
                point = 0;
                break;
            case 2:
                point = 5;
                break;
            case 7:
                point = 6;
                break;
            case 0:
                point = 9;
                break;
            default:
                point = (short) (data[numRecord] - 2);
        }

        try {
            rafHypno.seek(512 + numRecord * 2);

            byteBuffer.putShort(point);

            rafHypno.write(byteBuffer.array());

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     *
     * @return true if there is a dedicated EDF file to backup this hypnogram
     */
    public boolean hasLinkedFile() {
        return rafHypno != null;
    }

    /**
     * @return whether it is possible to modify this hypnogram
     */
    public boolean isWritable() {
        if (polysomnograph == null || data == null) {
            return false;
        }
        if (data.length == 0 || !hasLinkedFile()) {
            return false;
        }
        return epochDuration == polysomnograph.getEpochDuration() && !readOnly;
    }

    public void updateTexts() {
        longLabels[0] = JEDFMainWindow.getLocalizedString("Unscored");
        longLabels[1] = JEDFMainWindow.getLocalizedString("Awake");
        longLabels[2] = JEDFMainWindow.getLocalizedString("Rem");
        longLabels[3] = JEDFMainWindow.getLocalizedString("Stage 1");
        longLabels[4] = JEDFMainWindow.getLocalizedString("Stage 2");
        longLabels[5] = JEDFMainWindow.getLocalizedString("Stage 3");
        longLabels[6] = JEDFMainWindow.getLocalizedString("Stage 4");
        longLabels[7] = JEDFMainWindow.getLocalizedString("Movement");
        //stagesPanel.updateLabels(getLabels());
        updateStagesPanel();
    }

    public int getCurrentRecord() {
        return polysomnograph.getNavigationSlider().getValue() / epochDuration; //polysomnograph.getNbSecondsToDisplay();
    }

    public int getValue(int numEpoch) {
        return data[numEpoch];
    }

    public int getNbRecords() {
        if (data == null) {
            return 0;
        }
        return data.length;
    }

    public String getFilenameGabarito() {
        return m_srtFilenameGabarito;
    }

    public void setFilenameGabarito(String m_srtFilenameGabarito) {
        this.m_srtFilenameGabarito = m_srtFilenameGabarito;
    }
}
